#pragma once

#include "exports.hpp"
#include "Commands.hpp"
#include "Responses.hpp"




namespace Engine
{
	namespace Debugger
	{
		struct Direction
		{
			enum Type
			{
				ReadOnly,
				WriteOnly,
			};
		};
		///////////////////////////////////////////////////////////////////////////////////////////

		class queue_full
			: public std::exception
		{};
		///////////////////////////////////////////////////////////////////////////////////////////

		template <typename Elem, Direction::Type direction>
		class Queue;

		template <typename Elem>
		class Queue<Elem, Direction::WriteOnly>
		{
		public:

			typedef boost::shared_ptr<Queue<Elem, Direction::WriteOnly>>   ptr;



			Queue() {}
			virtual ~Queue() {}



			/**
			 * @returns the type of this queue (reading or writing)
			 */
			Direction::Type type() const { return Direction::WriteOnly; }



			/**
			 * Writes the given element into the queue.
			 * In case the queue is full, the function blocks
			 * until the element can be written into the queue.
			 *
			 * @throws queue_full in case no more elements can be added to the queue
			 */
			virtual Queue<Elem, Direction::WriteOnly>& operator<<(const Elem& elem) = 0;
		};
		///////////////////////////////////////////////////////////////////////////////////////////

		template <typename Elem>
		class Queue<Elem, Direction::ReadOnly>
		{
		public:

			typedef boost::shared_ptr<Queue<Elem, Direction::ReadOnly>>   ptr;

		public:

			Queue() {}
			virtual ~Queue() {}



			/**
			 * @returns the type of this queue (reading or writing)
			 */
			Direction::Type type() const { return Direction::ReadOnly; }

			/**
			 * Reads an element from the queue. Due to the polymorphic implementation
			 * of elements, the actual element is stored in a shared_ptr.
			 * Doesn't block if the queue is empty, instead the ptr is left untouched.
			 *
			 * @throws in case the queue is WriteOnly
			 */
			virtual Queue<Elem, Direction::ReadOnly>& operator>>(boost::shared_ptr<Elem>& elem) = 0;
		};
		///////////////////////////////////////////////////////////////////////////////////////////

		template class ENGINE_DEBUGGER_API Queue<Message, Direction::ReadOnly>;
		template class ENGINE_DEBUGGER_API Queue<Message, Direction::WriteOnly>;

		typedef Queue<Message, Direction::ReadOnly>     MessageReader;
		typedef Queue<Message, Direction::WriteOnly>    MessageWriter;
	}
	///////////////////////////////////////////////////////////////////////////////////////////////
}
///////////////////////////////////////////////////////////////////////////////////////////////////
